﻿// Copyright (C) Jari Hautio <jari.hautio@iki.fi> 2009. Licensed under GPLv2. See LICENSE.txt in solution folder.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Drawing.Imaging;

namespace ColorPicker
{
    interface IImageFilter
    {
         unsafe void Apply(Bitmap bm);
    }
    interface IColorFilter
    {
         void Apply(ref Color c);
    }
    class NullColorFilter : IColorFilter
    {

        #region IColorFilter Members

        public void Apply(ref Color c)
        {
        }

        #endregion
    }
    class ReplaceColorFilter : IColorFilter
    {
        List<Color> colors;
        ColorLib.FastColorTable table = new ColorLib.FastColorTable(6);
        ColorLib.ColorCube cc = new ColorLib.ColorCube();
        public ReplaceColorFilter(List<Color> newColors)
        {
            colors = newColors;
            foreach (Color c in colors)
                cc.Add(c);
        }

        /// <summary>
        /// Finds best matching color from the palette.
        /// </summary>
        /// <param name="c">Color to be matched</param>
        /// <returns>Best match color</returns>
        public Color FindMatch(Color c)
        {
            Color best = c;
            double dist = 256 * 256 * 4 + 1000;
            List<Color> lc = cc.Find(c);
            foreach (Color c2 in lc)
            {
                double d = Distance(c, c2);
                if (d < dist)
                {
                    dist = d;
                    best = c2;
                    if (dist == 0) break;
                }
            }
            return best;
        }
        /// <summary>
        /// Calculates distance betweemn two colors.
        /// </summary>
        /// <param name="c1"></param>
        /// <param name="c2"></param>
        /// <returns></returns>
        double Distance(Color c1, Color c2)
        {
            return ColorLib.ColorMath.DistanceRGB(c1, c2);
        }

        #region IColorFilter Members

        public void Apply(ref Color c)
        {
            Color c2 =/* FindMatch(c);*/ table.Get(c);
            if (c2 == Color.Empty)
            {
                c2 = FindMatch(c);
                table.Add(c, c2);
            }
            c = c2;
        }

        #endregion
    }
    class RecolorFilter : IImageFilter
    {

        private IColorFilter myFilter = new NullColorFilter();

        public IColorFilter ColorFilter
        {
            get { return myFilter; }
            set { myFilter = value; }
        }
	
        #region IImageFilter Members
        public unsafe void Apply(Bitmap bm)
        {
            if (bm == null) return;
            BitmapData bd = bm.LockBits(new Rectangle(0, 0, bm.Width, bm.Height),
                ImageLockMode.ReadWrite,
                PixelFormat.Format24bppRgb);
            byte* ptr = (byte*)bd.Scan0.ToPointer();
            int offset = bd.Stride - bm.Width * 3;
            int height = bm.Height;
            int width = bm.Width;
            for (int i = 0; i < height; i++)
            {
                for (int j = 0; j < width; j++)
                {
                    Color c = Color.FromArgb(ptr[2], ptr[1], ptr[0]);

                    myFilter.Apply(ref c);    
                    ptr[0] = c.B;
                    ptr[1] = c.G;
                    ptr[2] = c.R;
                    ptr += 3;
                }
                ptr += offset;
            }
            bm.UnlockBits(bd);            
        }

        #endregion
    }

}
